package cn.zhfeat.framework.shiro.base;

import cn.zhfeat.framework.shiro.util.ShiroSerializeUtil;
import cn.zhfeat.utils.cache.CacheUtility;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author ZhangHao
 * @version 1.0.0.1
 * @description: 我们自定义RedisSessionDAO继承AbstractSessionDAO，重写对session操作的方法，在应用中只要操作session，实际在方法中已经用redis处理了，
 * 可以用redis、mongoDB等进行实现。
 * <p>
 * 由Redis来管理session，包括session创建、读取、删除等，
 * 还可以统计在线用户，下面是核心代码RedisSessionDao的实现
 * <p>
 * 所谓会话，即用户访问应用时保持的连接关系，在多次交互中应用能够识别出当前访问的用户是谁，
 * 且可以在多次交互中保存一些数据。如访问一些网站时登录成功后，网站可以记住用户，且在退出之前都可以识别当前用户是谁。
 * @date 2018年5月14日 上午11:18:02
 */
@SuppressWarnings("unchecked")
@Component
public class RedisSessionDAO extends AbstractSessionDAO {
    private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);

    @Autowired
    private CacheUtility cacheUtility;

    private String categoryKey = "Shiro-Session";    //缓存类别
    private String cacheKey = "User-Info";        //缓存功能
    private String redisCacheListKey = "User-Session-Id-"; //自定义的Cache List的key


    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }

    
    /**
     * @description: 将session序列化保存进redis
     *
     * @param session
     * @throws UnknownSessionException 
     * @author ZhangHao
     * @date 2018年6月1日 下午3:25:28 
     * @version 1.0.0.1
     */
    private void saveSession(Session session) throws UnknownSessionException {
        if (session == null || session.getId() == null) {
            logger.error("session or session id is null");
            return;
        }

        try {
            cacheUtility.getCacheDataManager().putStringValue(categoryKey, cacheKey, redisCacheListKey + session.getId(), 7, TimeUnit.DAYS, ShiroSerializeUtil.serializeToString(session));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * @description:根据sessionId从redis中删除session 
     *
     * @param session 
     * @author ZhangHao
     * @date 2018年6月1日 下午3:25:41 
     * @version 1.0.0.1
     */
    @Override
    public void delete(Session session) {
        if (session == null || session.getId() == null) {
            logger.error("session or session id is null");
            return;
        }
        try {
            cacheUtility.getCacheDataManager().removeValue(categoryKey, cacheKey, redisCacheListKey + session.getId());
		} catch (Exception e) {
			e.printStackTrace();
		}

    }

    /**
     * @description: 从redis中获取全部的在线用户，并放入session
     *
     * @return 
     * @author ZhangHao
     * @date 2018年6月1日 下午3:25:51 
     * @version 1.0.0.1
     */
    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<Session>();
        List<Object> stringList = cacheUtility.getCacheDataManager().getStringValues(categoryKey, cacheKey, redisCacheListKey + "*");


        if (stringList != null && stringList.size() > 0) {
            for (Object obj : stringList) {
                Session s = null;
                try {
                    s = (Session) ShiroSerializeUtil.deserializeToObject((String) obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                sessions.add(s);
            }
        }

        return sessions;
    }

    /**
     * @description: 在redis中创建session
     *
     * @param session
     * @return 
     * @author ZhangHao
     * @date 2018年6月1日 下午3:25:58 
     * @version 1.0.0.1
     */
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        this.saveSession(session);
        return sessionId;
    }

    /**
     * @description: 根据序列化session从redis中获取系统中的Session
     *
     * @param sessionId
     * @return 
     * @author ZhangHao
     * @date 2018年6月1日 下午3:26:04 
     * @version 1.0.0.1
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            logger.error("session id is null");
            return null;
        }
        Session s = null;
        try {
            s = (Session) ShiroSerializeUtil.deserializeToObject((String) cacheUtility.getCacheDataManager().getStringValue(categoryKey, cacheKey, redisCacheListKey + sessionId));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }

}
